<?php
namespace app\libs;

/**
 * 验证码
 */
class VerifyCode {
    private $width;
    private $height;
    private $verifyCodeNum;  // 验证码字符个数
    private $img;  // 图像资源
    private $disturbDotNum;  // 干扰点个数
    private $arc;  // 是否画弧线干扰
    private $verifyCodes;  // 验证码

    public function __construct($width=80,$height=36,$verifyCodeNum=4,$arc=false) {
        $this->width = $width;
        $this->height = $height;
        $this->verifyCodeNum = $verifyCodeNum;
        $this->arc = $arc;

        //貌似php中设置颜色的总共次数是240 250次左右
        $number = floor($width*$height/20);
        if($number > 240-$verifyCodeNum) {
            $this->disturbDotNum = 240-$verifyCodeNum;
        } else {
            $this->disturbDotNum = $number;
        }
        $this->verifyCodes = $this->productCode();
    }

    // 创建画布
    private function createImage() {
        // 创建图像资源
        $this->img = imagecreatetruecolor($this->width, $this->height);
        $borderColor = imagecolorallocate($this->img, 0, 0, 0);  // 创建颜色
        $backColor = imagecolorallocate($this->img, mt_rand(225,255), mt_rand(225,255), mt_rand(225,255));
        // 填充背景色 这时才真正有颜色
        imagefill($this->img,0,0,$backColor);
        // 添加边框
        imagerectangle($this->img,0,0,$this->width-1,$this->height-1,$borderColor);
    }

    // 设置干扰元素
    private function setDisturbInfo() {
        // 画干扰点
        for($i=0;$i<$this->disturbDotNum;$i++) {
            $dotColor = imagecolorallocate($this->img, mt_rand(0,255), mt_rand(0,255), mt_rand(0,255));
            imagesetpixel($this->img, mt_rand(1,$this->width-2), mt_rand(1,$this->height-2), $dotColor);
        }
        // 画弧线
        if($this->arc) {
            for($i=0;$i<3;$i++) {
                $arcColor = imagecolorallocate($this->img,mt_rand(0,255),mt_rand(0,255),mt_rand(0,255));
                // 1 资源  2-3 圆心位置  4-5 圆弧宽度和高度  6-7 角度  8 颜色
                imagearc($this->img,mt_rand(-5,$this->width+5),mt_rand(-5,$this->height+5),
                    mt_rand(floor($this->width/2),$this->width+60),mt_rand(floor($this->height/2),$this->height+20),30,150,$arcColor);
            }
        }

    }

    // 设置随机文本
    private function setText($fontFace = '') {
        for($i=0; $i<$this->verifyCodeNum; $i++) {
            $fontColor = imagecolorallocate($this->img, mt_rand(0,100), mt_rand(0,100), mt_rand(0,120));
            if(empty($fontFace)) {
                $fontSize = mt_rand(16,20);  // 非像素
                $x = floor($this->width / $this->verifyCodeNum * $i + 3);  // 横坐标开始位置
                $y = mt_rand(2,$this->height - 15);  // 纵坐标开始位置
                imagechar($this->img, $fontSize, $x, $y, substr($this->verifyCodes,$i,1), $fontColor);
            } else {
                $fontSize = mt_rand(15, 17);  // 字体大小 像素
                $x = floor(($this->width-8) / $this->verifyCodeNum * $i + 8);  // 因为字体要倾斜所以留出8像素
                $y = mt_rand($fontSize, $this->height - 4);
                imagettftext($this->img, $fontSize, mt_rand(-10,10),
                        $x, $y, $fontColor, $fontFace, substr($this->verifyCodes,$i,1));
            }
        }
    }
    // 输出图像
    private function outputImage() {
        if(imagetypes() & IMG_GIF) {
            header("Content-Type: image/gif");
            imagegif($this->img);
        } else if(imagetypes() & IMG_JPG) {
            header("Content-Type: image/jpeg");
            imagejpeg($this->img);
        } else if(imagetypes() & IMG_PNG) {
            header("Content-Type: image/png");
            imagepng($this->img);
        } else {
            die('php不支持图像');
        }
    }

    // 得到验证码字符串
    private function productCode() {
        $code = '23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ';
        $chars = '';
        for($i=0; $i<$this->verifyCodeNum; $i++) {
            $chars .= substr($code, mt_rand(0, strlen($code)-1), 1);
        }
        return $chars;
    }

    // 关闭资源
    private function close() {
        if(isset($this->img)) {
            imagedestroy($this->img);
            $this->img = null;
        }
    }

    function __destruct() {
        if(isset($this->img)) {
            imagedestroy($this->img);
        }
    }

    // API
    // 输出验证码图片
    public function showVerifyCodeImage($fontFace='') {
        // 1. 创建图片and背景
        $this->createImage();
        // 2. 设置干扰元素
        $this->setDisturbInfo();
        // 3. 输出随机文本
        $this->setText($fontFace);
        // 4. 输出图像
        $this->outputImage();
        // 5. 关闭资源
        $this->close();
    }

    // 获得验证码字符串
    public function getVerifyCodes() {
        return $this->verifyCodes;
    }
}
